//package jsu.weizixuan.likesystem.service.impl;
//
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import jakarta.servlet.http.HttpServletRequest;
//import jsu.weizixuan.likesystem.constant.ThumbConstant;
//import jsu.weizixuan.likesystem.manager.CacheManager;
//import jsu.weizixuan.likesystem.mapper.ThumbMapper;
//import jsu.weizixuan.likesystem.model.pojo.Blog;
//import jsu.weizixuan.likesystem.model.pojo.DoThumbRequest;
//import jsu.weizixuan.likesystem.model.pojo.Thumb;
//import jsu.weizixuan.likesystem.model.pojo.User;
//import jsu.weizixuan.likesystem.service.BlogService;
//import jsu.weizixuan.likesystem.service.ThumbService;
//import jsu.weizixuan.likesystem.service.UserService;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.support.TransactionTemplate;
//
///**
// * @author pine
// */
//@Service("thumbServiceLocalCache")
//@Slf4j
//@RequiredArgsConstructor
//public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
//        implements ThumbService {
//
//    private final UserService userService;
//
//    private final BlogService blogService;
//
//    private final TransactionTemplate transactionTemplate;
//
//    private final RedisTemplate<String, Object> redisTemplate;
//
//    private final CacheManager cacheManager;
//
//    /**
//     * 版本一：
//     * 上述代码中，注意:
//     * 1.我们先进行了参数校验和用户登录态的校验，之后加锁执行点赞逻辑。注意是否已点赞的逻辑要在锁里执行，否则会出现锁不住的情况。
//     * 2.为了方便控制事务的起始，这里使用了编程式事务，保证事务在锁里开始和结束，避免因为事务导致锁失效。
//     * 3.我们这里的锁是本地锁，在多实例的分布式场景下有可能会失效，所以也可以使用分布式锁替代，比如Redisson 。
//     * 补充一点知识细节，也是面试考点 -- 在事务内加锁可能导致锁失效的原理:
//     * 线程A获取锁 →执行数据库操作 →释放锁 → 事务提交
//     * 线程B在A释放锁后立即获取锁
//     * 在默认的隔离级别可重复读下，由于在A提交前B已经开启了事务，所以B此时只能读到A操作前的数据，导致重复操作
//     */
//    @Override
//    public Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
//        if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
//            throw new RuntimeException("参数错误");
//        }
//        User loginUser = userService.getLoginUser(request);
//        // 加锁
//        synchronized (loginUser.getId().toString().intern()) {
//
//            // 编程式事务
//            return transactionTemplate.execute(status -> {
//                Long blogId = doThumbRequest.getBlogId();
//                Boolean exists = this.hasThumb(blogId, loginUser.getId());
//                if (exists) {
//                    throw new RuntimeException("用户已点赞");
//                }
//
//                boolean update = blogService.lambdaUpdate()
//                        .eq(Blog::getId, blogId)
//                        .setSql("thumbCount = thumbCount + 1")
//                        .update();
//
//                Thumb thumb = new Thumb();
//                thumb.setUserId(loginUser.getId());
//                thumb.setBlogId(blogId);
//                boolean success = update && this.save(thumb);
//
//                // 点赞记录存入 Redis
//                if (success) {
//                    String hashKey = ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId();
//                    String fieldKey = blogId.toString();
//                    Long realThumbId = thumb.getId();
//                    redisTemplate.opsForHash().put(hashKey, fieldKey, realThumbId);
//                    cacheManager.putIfPresent(hashKey, fieldKey, realThumbId);
//                }
//                // 更新成功才执行
//                return success;
//            });
//        }
//    }
//
//    @Override
//    public Boolean undoThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
//        if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
//            throw new RuntimeException("参数错误");
//        }
//        User loginUser = userService.getLoginUser(request);
//        // 加锁
//        synchronized (loginUser.getId().toString().intern()) {
//
//            // 编程式事务
//            return transactionTemplate.execute(status -> {
//                Long blogId = doThumbRequest.getBlogId();
//                Object thumbIdObj = cacheManager.get(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString());
//                if (thumbIdObj == null || thumbIdObj.equals(ThumbConstant.UN_THUMB_CONSTANT)) {
//                    throw new RuntimeException("用户未点赞");
//                }
//                boolean update = blogService.lambdaUpdate()
//                        .eq(Blog::getId, blogId)
//                        .setSql("thumbCount = thumbCount - 1")
//                        .update();
//                boolean success = update && this.removeById((Long)thumbIdObj);
//
//                // 点赞记录从 Redis 删除
//                if (success) {
//                    String hashKey = ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId();
//                    String fieldKey = blogId.toString();
//                    redisTemplate.opsForHash().delete(hashKey, fieldKey);
//                    cacheManager.putIfPresent(hashKey, fieldKey, ThumbConstant.UN_THUMB_CONSTANT);
//                }
//                return success;
//            });
//        }
//    }
//
//    @Override
//    public Boolean hasThumb(Long blogId, Long userId) {
//        Object thumbIdObj = cacheManager.get(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString());
//        if (thumbIdObj == null) {
//            return false;
//        }
//        Long thumbId = Long.valueOf(thumbIdObj.toString());
//        return !thumbId.equals(ThumbConstant.UN_THUMB_CONSTANT);
//    }
//
//}
//
//
//
//
